瓦片预缓存 Sample详情
最后更新时间:2019年6月17日
功能介绍
在线地图服务是移动终端常用的出图方式,在线地图服务通常是以瓦片为出图单元,最终将瓦片按照一定的规则拼接出图。为了给用户提供流畅、高效、快速的地图浏览体验,MapGIS Mobile不仅采用了高性能的地图渲染引擎,还提供了自动缓存的策略。在加载在线瓦片地图时,系统会自动将浏览过的范围、级别的地图进行自动缓存,存储到移动设备中,再次显示该区域的地图时直接读取离线本地数据,不用请求在线服务,从而使得地图能够非常迅速地渲染展示。这是MapGIS Mobile提供的自动缓存策略,存在一定的局限性,对于没有浏览过的区域的地图不会进行缓存。这无法满足要求在断网情况下同样能够浏览任意级别、任意区域地图的场景。所以MapGIS Mobile提供了瓦片预缓存的功能。
为了提高在线瓦片地图的加载速度,地图瓦片可以在终端预生成本地缓存,客户端浏览地图时可直接读取,这种技术被称作为瓦片预缓存技术。对于移动端来说,受限于硬件水平、网络速度、存储空间等因素,实现与PC终端相同的地图浏览及交互体验却相当困难,瓦片预缓存技术便在一定程度上解决了上述问题;另一方面,瓦片预缓存在在线浏览地图时动态缓存到本地存储,当在离线的时候亦可以浏览相同地图,这在野外作业中尤为重要。
瓦片预缓存实现的原理:在网络通畅情况下,根据用户需求,按照范围、级别将在线地图瓦片在终端生成本地缓存瓦片,存储到本地数据库中。从而在网络未连接的情况下,客户端直接读取本地缓存瓦片,同样能够进行地图的展示浏览。
MapGIS Mobile支持多种来源的在线地图,其中能够使用瓦片预缓存功能的数据类型包括:MapGIS IGServer在线瓦片地图、WMS地图服务、WMTS地图服务、天地图、Google地图、百度地图、高德地图、OSM地图、Bing地图等。
在缓存时,可以设置地图的级别范围、地图范围来实现更精确、更有针对性的瓦片缓存。
功能接口
瓦片预缓存功能对应API程序包为com.zondy.mapgis.core.map,其核心类为服务图层类ServerLayer,核心接口如下所示:
接口 | 说明 |
---|---|
setCacheLocation() | 设置缓存路径 |
setTilePreFetchListener() | 设置预缓存状态监听 |
preFetch() | 预缓存 |
stopFetch() | 停止预缓存 |
clearCache() | 清除缓存 |
实现方法
瓦片预缓存的大体实现方法如下所示:
(1)加载地图:首先需要加载能够进行瓦片预缓存功能的在线地图,并获取待进行缓存的ServerLayer图层对象;
(2)准备预缓存条件:选择需要缓存的地图范围、瓦片级别范围;
(3)设置监听:利用setTilePreFetchListener接口监听瓦片缓存的进度、状态;
(4)开始缓存:调用preFetch方法开始缓存;
(5)显示缓存:在缓存完成之后,可调用缓存进行显示。
实现过程
1
加载在线瓦片地图,以IGServer瓦片地图服务为例。
//地图服务对象 MapServer mapServer = ServerLayer.createMapServer(MapServer.MAPSERVER_TYPE_IGSERVER_TILE); //设置地图服务地址 mapServer.setURL("http://develop.smaryun.com:6163/igs/rest/mrms/tile/WorldJWTile"); //为mapserver设置名称,创建的缓存文件会使用到此名称 mapServer.setName("IGServer瓦片服务"); //服务图层:igserver中发布的瓦片服务 ServerLayer serverLayer = new ServerLayer(); //设置缓存路径 serverLayer.setCacheLocation(FilePath.PHONE_SDCARD_PATH + "/MapGIS Mobile 2D Sample/TileCache/"); //为服务图层设置地图服务 serverLayer.setMapServer(mapServer); //地图对象 map = new Map(); map.append(serverLayer); //加载地图 mapView.setMapAsync(map, new MapViewFinishCallback() { @Override public void onDidFinish(boolean arg0) { if (arg0) { //地图加载成功 } } });
代码说明:(1)进行瓦片预缓存的ServerLayer服务图层,需定义为成员变量。(2)设置缓存路径必须要在调用setMapServer之前执行,因为调用setMapServer的时候就会自动创建缓存了。
2
在进行瓦片缓存时,需要设置缓存的地图范围,由于瓦片地图采用了分级显示的机制,所以进行缓存时,也需要选择缓存的瓦片级别。在缓存时将会只缓存此地图范围内设置的级别的地图。设置的地图范围越小,缓存消耗时间越少,缓存后的文件数据量越小。选择的瓦片级别范围越多,消耗时间越多。级别越大的瓦片,缓存时消耗的时间越多。根据实际需求选择合理的地图范围、瓦片级别范围。
private void getServerInfo(ServerLayer serverlayer) { //获取地图服务对象 final MapServer mapServer = serverlayer.getMapServer(); //连接数据,在缓存igserver中的瓦片服务的时候需要使用 new Thread(new Runnable() { @Override public void run() { //需要先成功连接数据,才能获取其信息 long a = mapServer.connectData(); if (a > 0) { Message m = new Message(); m.what = 1; mhandler.sendMessage(m); } else { //连接数据失败,请确保网络已连接 } } }).start(); mhandler = new Handler() { public void handleMessage(Message msg) { super.handleMessage(msg); //转换为瓦片服务,获取最小最大级别 if (mapServer instanceof TileMapServer) { TileMapServer tileServer = (TileMapServer) mapServer; minZoom = tileServer.getMinZoom(); maxZoom = tileServer.getMaxZoom(); } } }; }
3
在缓存之前,调用setTilePreFetchListener接口为服务图层设置缓存监听器,在其回调函数中可获取缓存的状态、进度、结果信息。需注意的是这些回调函数都是在子线程中执行的,所以如果需要讲缓存进度信息展示在视图中,需在主线程中处理。
//设置预缓存状态监听 serverLayer.setTilePreFetchListener(tilePreFetchListener); //瓦片缓存监听器 TilePreFetchListener tilePreFetchListener = new TilePreFetchListener() { /** * 预缓存进度监听 * * @param lTaskID 任务ID,参见:ServerLayer.preFetch() * @param lTotalTileCount 待预缓存的瓦片总数 * @param lCurTileIndex 当前缓存的瓦片索引,从0开始 * @param dCurTileFetchProgress 当前缓存进度[0,100] */ public void onProgressing(int lTaskID, int lTotalTileCount, int lCurTileIndex, final double dCurTileFetchProgress) { Log.e("PreFetch", "预缓存进度:任务ID:" + lTaskID + ",待预缓存的瓦片总数:" + lTotalTileCount + ",当前缓存的瓦片索引:" + lCurTileIndex + ",当前缓存进度:" + dCurTileFetchProgress); } /** * 缓存状态监听 * * @param lTaskID 任务ID,参见:ServerLayer.preFetch() * @param lZoom 当前缓存瓦片的级别 * @param lRow 当前缓存瓦片的行号 * @param lCol 当前缓存瓦片的列号 * @param iStatus 当前缓存瓦片的状态:0:成功,1:获取瓦片失败,2:写入失败. */ public void onTileFetched(int lTaskID, int lZoom, int lRow, int lCol, short iStatus) { Log.e("PreFetch", "缓存状态:任务ID:" + lTaskID + ",当前缓存瓦片级别:" + lZoom + ",当前缓存瓦片行号:" + lRow + ",当前缓存瓦片列号:" + lCol + ",当前缓存瓦片状态:" + iStatus); } /** * 预缓存结束监听 * * @param lTaskID 任务ID,参见:ServerLayer.preFetch() * @param iFinishStatus 0:正常结束,1:非正常结束 */ public void onFetchFinish(int lTaskID, short iFinishStatus) { Log.e("PreFetch", "预缓存结束监听:任务ID:" + lTaskID + ",缓存结果:" + iFinishStatus); if (lTaskID == taskID) { if (iFinishStatus == 0){ //缓存成功 } } } };
4
准备工作完成后,可调用preFetch方法,指定缓存的最小最大级别、地图空间范围开始缓存,返回值为缓存的任务ID。缓存的级别可从第0级到第0级,下载的即为第0级的瓦片。在缓存时,需要确保网络状态良好,避免造成缓存失败的情况。
/** * 预缓存(异步方法) * 参数:预缓存的最小级别,预缓存的最大级别,预缓存的空间范围 */ int taskID = serverLayer.preFetch(min, max, rect);
5
根据缓存监听可判断缓存结果,缓存成功完成后,会在缓存路径中生成一个“**.mtdb”缓存文件。缓存完成后,可调用离线缓存,在未连接网络时同样能够显示地图。
在调用缓存显示地图时,与普通的通过在线请求显示地图方法类似,另外需调用setAccessMode方法设置从缓存中读取数据,并调用setCacheLocation方法设置缓存数据存在的路径,关键代码如下所示:
//地图服务对象 MapServer mapServer = ServerLayer.createMapServer(MapServer.MAPSERVER_TYPE_IGSERVER_TILE); //设置地图服务地址 mapServer.setURL("http://develop.smaryun.com:6163/igs/rest/mrms/tile/WorldJWTile"); //为mapserver设置名称,创建的缓存文件会使用到此名称 mapServer.setName("IGServer瓦片服务"); //服务图层:igserver中发布的瓦片服务 ServerLayer serverLayer = new ServerLayer(); //设置服务图层的数据只从缓存中读取 serverLayer.setAccessMode(MapServerAccessMode.CacheOnly); //设置缓存数据的路径 serverLayer.setCacheLocation(FilePath.PHONE_SDCARD_PATH + "/MapGIS Mobile 2D Sample/TileCache/"); //为服务图层设置地图服务 serverLayer.setMapServer(mapServer); //地图对象 map = new Map(); map.append(serverLayer); //加载地图 mapView.setMapAsync(map, new MapViewFinishCallback() { @Override public void onDidFinish(boolean arg0) { if (arg0) { //地图加载成功 } } });